use std::sync::{Arc, Mutex};

use crate::classfile;

use super::{ClassRef, ConstantPool, Constant, Class};

#[derive(Default, Clone)]
pub struct ExceptionTable(Vec<ExceptionHandler>);

#[derive(Clone)]
pub struct ExceptionHandler {
    pub start_pc: i32,
    pub end_pc: i32,
    pub handler_pc: i32,
    pub catch_type: Option<Arc<Mutex<ClassRef>>>,
}

impl ExceptionTable {
    pub fn new_exception_table(entries: &Vec<classfile::ExceptionTableEntry>,  cp: Arc<ConstantPool>) -> ExceptionTable {
        let table = entries.iter()
            .map(|entry| 
                ExceptionHandler {
                    start_pc: entry.start_pc as i32,
                    end_pc: entry.end_pc as i32,
                    handler_pc: entry.handler_pc as i32,
                    catch_type: Self::get_catch_type(entry.catch_type as usize, cp.clone()),
                }
            ).collect();
        ExceptionTable(table)
    }    

    fn get_catch_type(index: usize, cp: Arc<ConstantPool>) -> Option<Arc<Mutex<ClassRef>>> {
        // 0 常量池0位置为None 表示catch-all
        if index == 0 {
            return None;
        }
        if let Some(Constant::ClassRef(val)) = cp.get_constant(index) {
            return Some(val);
        }
        None
    }

    pub fn find_exception_handler(&self, ex_class: Arc<Class>, pc: i32) -> Option<&ExceptionHandler> {
        for handler in &self.0 {
            if pc > handler.start_pc && pc < handler.end_pc {
                if handler.catch_type.is_none() {
                    return Some(handler); // catch-all
                }
                let catch_class = handler.catch_type.as_ref().unwrap().lock().unwrap().resolved_class();
                // catchClass是exClass或其父级
                if Arc::ptr_eq(&ex_class, &catch_class) || ex_class.is_sub_class_of(&catch_class) {
                    return Some(handler);
                }
            }
        }
        None
    }
}